home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / cpp_libs / intrvews / xgrab.lha / xgrab / ui / ps.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-03-07  |  25.4 KB  |  1,021 lines

  1. /**
  2.    GRAB Graph Layout and Browser System
  3.  
  4.    Copyright (c) 1986, 1988 Regents of the University of California
  5.    Copyright (c) 1989, Tera Computer Company
  6.  **/
  7.  
  8.   /** 
  9.      ps.c contains procedures to draw a layed out digraph into a postscript 
  10.      file.
  11.  
  12.      Portions of this file were adapted from previously copyrighted material.
  13.      These are denoted by the comments "begin f2ps material" and 
  14.      "end f2ps material".   The original copyright notice follows:
  15.  
  16.         F2ps : Fig-to-PostScript translator
  17.     
  18.         Copyright (c) 1986 by Supoj Sutanthavibul (supoj@sally.UTEXAS.EDU)
  19.         June 1986.
  20.         1st revision : March 1988 - read fig 1.4
  21.     
  22.         %W    %G%
  23.     
  24.    **/
  25.  
  26. #include "malloc.h"
  27. #include <sys/file.h>
  28. #include <stdio.h>
  29. #include <pwd.h>
  30. #include <math.h>
  31. #include <string.h>
  32. #include <time.h>
  33.  
  34. #include "attribute.h"
  35. #include "digraph.h"
  36. #include "screen.h"
  37. #include "globals.h"
  38. #include "scrdep.h"
  39. #include "ps.h"
  40. #include "interf.h"
  41.  
  42. static FILE *psfile;
  43. static char psname[MAXSTR];
  44. static double charxsize;        /* character width */
  45. static double charysize;        /* character height */
  46. static double echarxsize;         /* edge label character width */
  47. static double echarysize;         /* edge label character height */
  48. static double curcharxsize;         /* current valid character width */
  49. static double curcharysize;         /* current valid character height */
  50. #define FUDGE 1.8        
  51.   /**
  52.      with variable-sized fonts, you fit more characters in the x
  53.      dimension as the y (given an aspect ratio of one).  We can use this 
  54.      fudge factor to increase the size of the font and still keep the text 
  55.      the proper size 
  56.    **/
  57.  
  58. OUTEDGE *get_edge();
  59.  
  60. static int llx, lly, urx, ury;
  61. static double scalex, scaley;
  62.  
  63.   /* begin f2ps material */
  64.  
  65. #define    PAGE_WIDTH 612            /* points; 8.5" */
  66. #define    PAGE_HEIGHT 792            /* points; 11" */
  67. #define    POINT_PER_INCH 72
  68. #define    DEFAULT_FONT "Times-Roman"
  69.  
  70. char *font = DEFAULT_FONT;
  71. float cur_thickness;
  72. BOOL show_page = TRUE;
  73. BOOL ellipse_exist();
  74.  
  75. #define    TEXT_PS        "\
  76. /%s findfont %f scalefont def\n\
  77. "
  78.  
  79. #define        BEGIN_PROLOG    "\
  80. /$XgrabpsDict 32 dict def \
  81. $XgrabpsDict begin\
  82.  $XgrabpsDict /mtrx matrix put\
  83. "
  84. #define        ELLIPSE_PS    " \
  85. /DrawEllipse {\
  86.  /endangle exch def\
  87.  /startangle exch def\
  88.  /yrad exch def\
  89.  /xrad exch def\
  90.  /y exch def\
  91.  /x exch def\
  92.  /savematrix mtrx currentmatrix def\
  93.  x y translate xrad yrad scale 0 0 1 startangle endangle arc\
  94.  savematrix setmatrix\
  95.  } def\
  96. "
  97. #define        END_PROLOG    "\
  98.  end\
  99.  /$XgrabpsBegin {$XgrabpsDict begin /$XgrabpsEnteredState save def} def\
  100.  /$XgrabpsEnd {$XgrabpsEnteredState restore end} def\
  101. \n%%EndProlog\
  102. "
  103.  
  104.   /* end f2ps material */
  105.  
  106.  
  107. #define LEFT_MARGIN 1 * POINT_PER_INCH       /* margins, in points */
  108. #define RIGHT_MARGIN 1 * POINT_PER_INCH        
  109. #define TOP_MARGIN 1 * POINT_PER_INCH    
  110. #define BOTTOM_MARGIN 1    * POINT_PER_INCH
  111. #define LABELX 20            /* extra room for edge/node labels */
  112. #define LABELY 8            /* extra room for edge/node labels */
  113.  
  114. #define MAXCHT 24.0        /* characters are really obnoxious if they're
  115.                    bigger than this */
  116. #define MAXELHT 8.0        /* edge labels should stay small */
  117. #define MINCHT 4.0        /* can't read characters with width or height
  118.                    smaller than this */
  119.  
  120. #define DB_MARGIN 2.0        /* distance from inner to outer rectangle 
  121.                    for a double box node */
  122.  
  123. #define    DEFAULT_PS_FONT "-adobe-times-medium-r-normal--10-100-75-75-p-54-iso8859-1"        /* to use fonthandler.c to get a size in the X dimension */
  124. #define    DEFAULT_PS_FONT_SIZE 10.0    /* 10 point font used for sizing */
  125.  
  126. char *psfont = DEFAULT_PS_FONT;
  127.  
  128. static BOOL firstText = TRUE;
  129. static BOOL nodeOnly;
  130.  
  131.   /** 
  132.      DrawScreenPS draws what you see on the screen on one page.
  133.      DrawGraphPS draws the entire graph on one page.
  134.      The only differences are the names of the output files and the
  135.      bounding boxes.
  136.    **/
  137.  
  138. DrawScreenPS(digraph, showbc)
  139. DIGRAPH* digraph;
  140. BOOL showbc;
  141. {
  142.     SCREEN psscreen;
  143.  
  144.     psscreen.absview.min_x = screen.bound.min_x;
  145.     psscreen.absview.min_y = screen.bound.min_y;
  146.     psscreen.absview.max_x = screen.bound.max_x;
  147.     psscreen.absview.max_y = screen.bound.max_y;
  148.  
  149.     DrawPS(digraph, showbc, &psscreen, "screen");
  150. }
  151.  
  152. DrawGraphPS(digraph, showbc)
  153. DIGRAPH* digraph;
  154. BOOL showbc;
  155. {
  156.     SCREEN psscreen;
  157.  
  158.     psscreen.absview.min_x = screen.absview.min_x;
  159.     psscreen.absview.min_y = screen.absview.min_y;
  160.     psscreen.absview.max_x = screen.absview.max_x;
  161.     psscreen.absview.max_y = screen.absview.max_y;
  162.  
  163.     DrawPS(digraph, showbc, &psscreen, name);
  164. }
  165.     
  166. DrawPS(digraph, showbc, psscreen, fname)
  167. DIGRAPH *digraph;
  168. BOOL showbc;         /* flag to show bc's */
  169. SCREEN *psscreen;
  170. char *fname;
  171.   /** 
  172.      write the portion of the graph denoted by psscreen in postscript format 
  173.      in file fname
  174.    **/
  175. {
  176.     NODE *node;     /* each node */
  177.     int cx, cy;
  178.     char *s;
  179.  
  180.     if (digraph == NULL) 
  181.     {
  182.     IChangeStatusLine("No digraph to draw", FALSE);
  183.     return;
  184.     }
  185.  
  186.     (void) strncpy(psname, fname, MAXSTR - 4);
  187.     (void) strcat(psname, ".ps");
  188.  
  189.     s = (char *) malloc(sizeof(char) * MAXLINE);
  190.  
  191.     if ((psfile = fopen(psname, "r")) != NULL) 
  192.     {
  193.     fclose(psfile);
  194.     sprintf(s, "File %s exists.  Overwrite?", psname);
  195.  
  196.         if (IConfirm(s) != 'y') 
  197.         {
  198.         return;
  199.     }
  200.     }
  201.  
  202.     if ((psfile = fopen(psname, "w")) == NULL) 
  203.     {
  204.     sprintf(s, "Couldn't open %s", psname);
  205.     IChangeStatusLine(s, FALSE);
  206.     dispose(s);
  207.     return;
  208.     }
  209.  
  210.     firstText = TRUE;
  211.     nodeOnly = FALSE;
  212.     cur_thickness = 0.0;
  213.  
  214.     if (landscapePSFile)
  215.       /* draw in 'landscape' mode (sideways) */
  216.     {
  217.     llx = BOTTOM_MARGIN;
  218.     lly = RIGHT_MARGIN + LABELY;
  219.     urx = PAGE_HEIGHT - (TOP_MARGIN + LABELX);
  220.     ury = PAGE_WIDTH - LEFT_MARGIN;
  221.     }
  222.     else
  223.     {
  224.     llx = LEFT_MARGIN;
  225.     lly = BOTTOM_MARGIN + LABELY;
  226.     urx = PAGE_WIDTH - (RIGHT_MARGIN + LABELX);
  227.     ury = PAGE_HEIGHT - TOP_MARGIN;
  228.     }
  229.  
  230.     psscreen->display.min_x = 0;
  231.     psscreen->display.min_y = 0;
  232.     psscreen->display.max_x = urx - llx;
  233.     psscreen->display.max_y = ury - lly;
  234.  
  235.     psscreen->canvas.min_x = llx;
  236.     psscreen->canvas.min_y = lly;
  237.     psscreen->canvas.max_x = urx;
  238.     psscreen->canvas.max_y = ury;
  239.  
  240.     psscreen->zoom.xzoom = (float) (psscreen->absview.max_x - 
  241.                     psscreen->absview.min_x) /
  242.                (float) (psscreen->canvas.max_x - 
  243.                     psscreen->canvas.min_x);
  244.     psscreen->zoom.yzoom = (float) (psscreen->absview.max_y - 
  245.                     psscreen->absview.min_y) /
  246.                (float) (psscreen->canvas.max_y - 
  247.                     psscreen->canvas.min_y);
  248.  
  249.     psscreen->bound.min_x = SCRX_TO_ABSX(psscreen, llx);
  250.     psscreen->bound.min_y = SCRY_TO_ABSY(psscreen, lly);
  251.     psscreen->bound.max_x = SCRX_TO_ABSX(psscreen, urx);
  252.     psscreen->bound.max_y = SCRY_TO_ABSY(psscreen, ury);
  253.  
  254.     scaley = psscreen->zoom.yzoom;
  255.     scalex = psscreen->zoom.xzoom;
  256.  
  257.     cy = get_height(digraph);
  258.     cx = HALF_CHAR * 2;        
  259.     charysize = (double) cy * 0.75 / scaley;    
  260.       /* characters are at most about 3/4 of the box */
  261.  
  262.       /* can't be too big for x, after x is resized */
  263.     if (charysize > (cx * FUDGE / scalex))      
  264.     {
  265.     charysize = cx * FUDGE / scalex;
  266.     }
  267.  
  268.     if ((charysize < MINCHT) && printNodeLabel)
  269.     {
  270.     nodeOnly = TRUE;    /* only want to see the nodes */
  271.     charysize = MINCHT;
  272.     }
  273.     else if (charysize > MAXCHT)
  274.     {
  275.     charysize = MAXCHT;    /* don't want text too big */
  276.     }
  277.  
  278.     charxsize = charysize;
  279.  
  280.     if (charysize > MAXELHT)    /* don't want edge labels too big */
  281.     {
  282.     echarysize = MAXELHT;
  283.     }
  284.     else
  285.     {
  286.     echarysize = charysize;
  287.     }
  288.  
  289.     echarxsize = echarysize;
  290.  
  291.     ISetPS(psfont);
  292.     curcharxsize = charxsize;
  293.     curcharysize = charysize;
  294.  
  295.   /* begin f2ps material */
  296.     prolog(digraph);
  297.   /* end f2ps material */
  298.  
  299.     fprintf(psfile, "Nodefont setfont\n");
  300.  
  301.     each_node(digraph, node)
  302.     loop
  303.         ps_draw_node(digraph, node, showbc, psscreen);
  304.         ps_draw_out_edges(digraph, node, psscreen);
  305.           /**
  306.          don't need to draw the in edges as we have already drawn all 
  307.              the edges by drawing the out edges 
  308.            **/
  309.     endloop
  310.  
  311.   /* begin f2ps material */
  312.     epilog();
  313.   /* end f2ps material */
  314.  
  315.     ps_close(psfile);
  316.  
  317.     sprintf(s, "%s created.", psname);
  318.     IChangeStatusLine(s, FALSE);
  319.     dispose(s);
  320. } /* DrawPS */
  321.  
  322. ps_draw_node(digraph, node, showbc, psscreen)
  323. DIGRAPH *digraph;
  324. NODE *node;     /* node to draw */
  325. BOOL showbc;    /* flag to show bc's */
  326. SCREEN *psscreen;
  327.   /**
  328.      ps_draw_node draws a node, including its name, outgoing edges, and
  329.      barycenters (optional).
  330.    **/
  331. {
  332.     switch (Shape(node))
  333.     {
  334.         case POINT:
  335.             break;
  336.         case OVAL:
  337.           ps_draw_oval((float) ABSX_TO_SCRX(psscreen, X_position(node)), 
  338.              (float) ABSY_TO_SCRY(psscreen, Y_position(node)),
  339.              (float) SCALE_X(psscreen, Half_width(node)),
  340.              (float) SCALE_Y(psscreen, Half_height(node)),
  341.              Brush(node), Color(node));
  342.             break;
  343.         case CIRCLE: 
  344.           ps_draw_oval((float) ABSX_TO_SCRX(psscreen, X_position(node)), 
  345.              (float) ABSY_TO_SCRY(psscreen, Y_position(node)),
  346.              (float) SCALE_Y(psscreen, Half_height(node)),
  347.              (float) SCALE_Y(psscreen, Half_height(node)),
  348.              Brush(node), Color(node));
  349.             break;
  350.         case DIAMOND:
  351.         ps_draw_diamond((float) ABSX_TO_SCRX(psscreen, X_position(node)), 
  352.                 (float) ABSY_TO_SCRY(psscreen, Y_position(node)),
  353.                 (float) ABSX_TO_SCRX(psscreen, X_left(node)), 
  354.                 (float) ABSY_TO_SCRY(psscreen, Y_bottom(node)),
  355.                 (float) ABSX_TO_SCRX(psscreen, X_right(node)),
  356.                 (float) ABSY_TO_SCRY(psscreen, Y_top(node)),
  357.                 Brush(node), Color(node));
  358.         break;
  359.         case DOUBLE_BOX:
  360.           /**
  361.          without the MINs and MAXs, it's possible for the top
  362.          of the inner rectangle to be below the bottom, and/or the
  363.          right to be to the left of the left (if the rectangle is 
  364.          very short or very skinny)
  365.            **/
  366.         ps_draw_rect(MIN((float) (ABSX_TO_SCRX(psscreen, X_left(node)) +
  367.                           (float) DB_MARGIN),
  368.                  (float) (ABSX_TO_SCRX(psscreen, 
  369.                                X_position(node)))),
  370.              MAX((float) (ABSX_TO_SCRX(psscreen, X_right(node)) - 
  371.                       (float) DB_MARGIN),
  372.                  (float) (ABSX_TO_SCRX(psscreen, 
  373.                                X_position(node)))),
  374.              MIN((float) (ABSY_TO_SCRY(psscreen, Y_bottom(node)) + 
  375.                       (float) DB_MARGIN), 
  376.                  (float) (ABSY_TO_SCRY(psscreen, 
  377.                                Y_position(node)))),
  378.              MAX((float) (ABSY_TO_SCRY(psscreen, Y_top(node)) - 
  379.                       (float) DB_MARGIN),
  380.                  (float) (ABSY_TO_SCRY(psscreen, 
  381.                                Y_position(node)))),
  382.                 Brush(node), Color(node));
  383.  
  384.         ps_draw_rect((float) ABSX_TO_SCRX(psscreen, X_left(node)), 
  385.              (float) ABSX_TO_SCRX(psscreen, X_right(node)),
  386.              (float) ABSY_TO_SCRY(psscreen, Y_bottom(node)), 
  387.              (float) ABSY_TO_SCRY(psscreen, Y_top(node)),
  388.              Brush(node), Color(node));
  389.             break;
  390.         case RECTANGLE:
  391.         ps_draw_rect((float) ABSX_TO_SCRX(psscreen, X_left(node)),
  392.              (float) ABSX_TO_SCRX(psscreen, X_right(node)),
  393.              (float) ABSY_TO_SCRY(psscreen, Y_bottom(node)),
  394.              (float) ABSY_TO_SCRY(psscreen, Y_top(node)),
  395.              Brush(node), Color(node));
  396.             break;
  397.         default:
  398.             perror("ps_draw_node:  illegal shape");
  399.         break;
  400.     }
  401.  
  402.     if (!(Is_dummy(node))) 
  403.     {
  404.     if (nodeOnly)
  405.       /**
  406.          if the text doesn't fit in the node, put it just below it and
  407.          to the right.
  408.        **/
  409.     {
  410.         if (Shape(node) == CIRCLE)
  411.         {
  412.                 ps_text(Text(node), 
  413.                 (double) ABSX_TO_SCRX(psscreen, X_position(node)) +
  414.             (double) SCALE_Y(psscreen, Half_height(node)),
  415.                 (double) ABSY_TO_SCRY(psscreen, Y_bottom(node)), 
  416.                 TOPLEFT, Color(node));
  417.         }
  418.         else
  419.         {
  420.                 ps_text(Text(node), 
  421.                 (double) ABSX_TO_SCRX(psscreen, X_right(node)), 
  422.                 (double) ABSY_TO_SCRY(psscreen, Y_bottom(node)), 
  423.                 TOPLEFT, Color(node));
  424.         }
  425.     }
  426.     else
  427.       /* otherwise, center it */
  428.     {
  429.             ps_text(Text(node), 
  430.             (double) ABSX_TO_SCRX(psscreen, X_position(node)),
  431.             (double) ABSY_TO_SCRY(psscreen, Y_position(node)), 
  432.             CENTCENT, Color(node));
  433.     }
  434.     }
  435.  
  436.     if (showbc && !nodeOnly)
  437.     {
  438.         ps_draw_barycenters(node, Color(node), psscreen);
  439.     }
  440. } /* ps_draw_node */
  441.  
  442.  
  443. ps_draw_barycenters(node, color, psscreen)
  444. NODE *node;
  445. COLOR color;
  446. SCREEN *psscreen;
  447.   /**
  448.      ps_draw_barycenters displays the priorities and barycenters above and
  449.      below a node.
  450.    **/
  451. {
  452.     char bc[20];     /* up or down bc */
  453.  
  454.     if (Bc(node, UP) != NO_BC)
  455.     {
  456.         sprintf(bc, "%d/%3.1f", Priority(node, UP), Bc(node, UP));
  457.         ps_text(bc, 
  458.         (double) ABSX_TO_SCRX(psscreen, X_position(node)),
  459.         (double) ABSY_TO_SCRY(psscreen, Y_top(node)),
  460.         CENTCENT, color);
  461.     }
  462.  
  463.     if (Bc(node, DOWN) != NO_BC)
  464.     {
  465.         sprintf(bc, "%d/%3.1f", Priority(node, DOWN), Bc(node, DOWN));
  466.         ps_text(bc, 
  467.         (double) ABSX_TO_SCRX(psscreen, X_position(node)),
  468.         (double) ABSY_TO_SCRY(psscreen, Y_bottom(node)),
  469.         CENTCENT, color);
  470.     }
  471. } /* draw_barycenters */
  472.  
  473. ps_draw_out_edges(digraph, node, psscreen)
  474. DIGRAPH *digraph;
  475. NODE *node;    /* node with edges */
  476. SCREEN *psscreen;
  477.   /* draw all the out edges of a node */
  478. {
  479.     VNO to_vno;    /* each succedent node */
  480.     NODE *tonode, *get_prev_node(), *get_next_node();
  481.     double from_x;
  482.     double from_y;
  483.     double to_x;
  484.     double to_y;
  485.     BOOL forward;
  486.     BOOL reversed;
  487.     BRUSH brush;
  488.     COLOR color;
  489.     OUTEDGE *e;
  490.     int i;
  491.  
  492.     each_element(Succ_set(node), to_vno)
  493.     loop
  494.         tonode = Node(digraph, to_vno);
  495.  
  496.         for (i = max_edges(node, tonode); i > 0; i--)
  497.     {
  498.             forward = FALSE;
  499.             reversed = FALSE;
  500.  
  501.               /* clip in both directions */
  502.         if ((e = get_edge(digraph, node, tonode, i)) != NULL)
  503.         {
  504.               Clip(node, tonode, i, &from_x, &from_y, &to_x, &to_y, psscreen);
  505.     
  506.           /**
  507.              should we draw the arrow forward, reversed, or not at
  508.              all?  outedge_reversed is false if the first node is a 
  509.              dummy node, so an edge from a dummy node will only have 
  510.              an arrow if tonode isn't a dummy node and the edge isn't 
  511.              reversed.
  512.            **/
  513.                 if (printArrow) 
  514.             {
  515.                 if (outedge_reversed(digraph, node, tonode, i)) 
  516.             {
  517.                 reversed = TRUE;
  518.                 } 
  519.                 else if (!Is_dummy(tonode)) 
  520.                 {
  521.                     NODE *prevnode;
  522.         
  523.                     if (Is_dummy(node)) 
  524.                 {
  525.                     prevnode = get_prev_node(digraph, node);
  526.                     } 
  527.                 else 
  528.                 {
  529.                     prevnode = node;
  530.                     }
  531.         
  532.                     if (!outedge_reversed(digraph, prevnode, tonode, i)) 
  533.                 {
  534.                     forward = TRUE;
  535.                     }
  536.                 }
  537.                 }
  538.  
  539.             brush = Brush(e);
  540.             color = Color(e);
  541.     
  542.                 ps_line((double) ABSX_TO_SCRX(psscreen, from_x),
  543.                 (double) ABSY_TO_SCRY(psscreen, from_y), 
  544.                 (double) ABSX_TO_SCRX(psscreen, to_x),
  545.                 (double) ABSY_TO_SCRY(psscreen, to_y), 
  546.                 reversed, forward, brush, color);
  547.     
  548.                 if (!Is_dummy(node) && printEdgeLabel && !nodeOnly)
  549.             {
  550.                 ps_draw_edge_label(digraph, node, tonode, i,
  551.                            (double) ABSX_TO_SCRX(psscreen, from_x),
  552.                            (double) ABSY_TO_SCRY(psscreen, from_y),
  553.                            (double) ABSX_TO_SCRX(psscreen, to_x),
  554.                            (double) ABSY_TO_SCRY(psscreen, to_y),
  555.                            color);
  556.                 }
  557.         }
  558.     }
  559.     endloop
  560. } /* draw_out_edges */
  561.     
  562. ps_draw_edge_label(digraph, node, tonode, ord, from_x, from_y, to_x, to_y, 
  563.     color)
  564. DIGRAPH *digraph;
  565. NODE *node, *tonode;
  566. int ord;
  567. double from_x, from_y, to_x, to_y;
  568. COLOR color;
  569. {
  570.     char *label;
  571.     double xpos, ypos, shift;
  572.     NODE *get_next_node();
  573.     char *get_edge_label();
  574.  
  575.     if (Is_dummy(tonode)) 
  576.     {
  577.     tonode = get_next_node(digraph, tonode);
  578.     }
  579.  
  580.     label = get_edge_label(digraph, node, tonode, ord);
  581.  
  582.     if (*label != '\0')
  583.     {
  584.         /**
  585.          multigraph support:  labels for edges should be staggered so
  586.          they don't overrun each other 
  587.        **/
  588.         shift = echarysize * (ord / 2) * ((ord % 2 == 0) ? -1 : 1);
  589.  
  590.     xpos = (double) (from_x + to_x) / 2.0;
  591.     ypos = (double) (from_y + to_y) / 2.0;
  592.  
  593.         if (from_y != to_y)
  594.         {
  595.         ypos += shift;
  596.         xpos += shift * (from_x - to_x) / (from_y - to_y);
  597.         }
  598.  
  599.     curcharxsize = echarxsize;
  600.     curcharysize = echarysize;
  601.  
  602.         fprintf(psfile, "Edgefont setfont\n");
  603.         ps_text(label, xpos, ypos, CENTLEFT, color);
  604.         fprintf(psfile, "Nodefont setfont\n");
  605.  
  606.     curcharxsize = charxsize;
  607.     curcharysize = charysize;
  608.     }
  609. }
  610.  
  611. ps_close(fp)
  612. FILE *fp;
  613.   /* close the file */
  614. {
  615.     if (fp == (FILE *) NULL) 
  616.     {
  617.     fprintf(stderr, "ps_close: NULL file pointer\n");
  618.     }
  619.  
  620.     fclose(fp);
  621. }
  622.  
  623. ps_text(text, x, y, justification, color)
  624. char *text;            /* text string */
  625. double x, y;            /* justification relative to this point */
  626. int justification;        /* type of justification */
  627. COLOR color;
  628.   /* draw the text at position <x, y> with the given color and justification */
  629. {
  630.     char *c;
  631.     double length;        /* length based on size */
  632.     double pos_x, pos_y;    /* lower left coordinate position of text */
  633.  
  634.     if (strlen(text) == 0) 
  635.     {
  636.     return;
  637.     }
  638.     else if ((justification < BOTLEFT) || (justification > BOTCENT) ||
  639.         ((justification > CENTCENT) && (justification < TOPLEFT))) 
  640.     {
  641.     fprintf(stderr, "ps_text: bad justification %d\n", justification);
  642.     }
  643.  
  644.     length = IWidthPS(text) * curcharxsize / DEFAULT_PS_FONT_SIZE;
  645.       /* call fonthandler.c to find the size of the text */
  646.  
  647.     switch (justification) 
  648.     {
  649.     case BOTLEFT:
  650.     case CENTLEFT:
  651.     case TOPLEFT:
  652.         pos_x = x;
  653.         break;
  654.     case BOTCENT:
  655.     case CENTCENT:
  656.     case TOPCENT: 
  657.         pos_x = x - (length / 2.0);
  658.         break;
  659.     case BOTRIGHT:
  660.     case CENTRIGHT:
  661.     case TOPRIGHT:
  662.         pos_x = x - length;
  663.         break;
  664.     }
  665.  
  666.     switch (justification) 
  667.     {
  668.     case BOTLEFT:
  669.     case BOTCENT:
  670.     case BOTRIGHT:
  671.         pos_y = y;
  672.         break;
  673.     case CENTLEFT:
  674.     case CENTCENT:
  675.     case CENTRIGHT:
  676.         pos_y = y - (curcharysize / 2.0);
  677.         break;
  678.     case TOPLEFT:
  679.     case TOPCENT:
  680.     case TOPRIGHT:
  681.         pos_y = y - curcharysize;;
  682.         break;
  683.     }
  684.  
  685.   /* begin f2ps material */
  686.     set_style(SOLIDB, color);
  687.     fprintf(psfile, "%f %f moveto (", pos_x, pos_y);
  688.  
  689.     for (c = text; *c; c++) 
  690.     {
  691.         if (*c == '\\' || *c == '(' || *c == ')') 
  692.         {
  693.             putc('\\', psfile);
  694.     }
  695.  
  696.     putc(*c, psfile);
  697.     }
  698.  
  699.     fprintf(psfile, ") show\n");
  700.  
  701.     reset_style(SOLIDB, color);
  702. }
  703.  
  704. prolog(digraph)
  705. DIGRAPH *digraph;
  706.   /* write the introductory postscript magic */
  707. {
  708.     char host[MAXSTR];
  709.     struct passwd *who;
  710.     long when;
  711.     extern char    *ctime();
  712.     extern long time();
  713.  
  714.     fprintf(psfile, "%%!PS-Adobe-1.0\n");    /* PostScript magic strings */
  715.     who = getpwuid(getuid());
  716.  
  717.     if (-1 == gethostname(host, sizeof(host)))
  718.     {
  719.         (void)strcpy(host, "unknown-host!?!?");
  720.     }
  721.  
  722.     (void) time(&when);
  723.     fprintf(psfile, "%%%%Title: %s\n", name);
  724.     fprintf(psfile, "%%%%Creator: Xgrab\n");
  725.     fprintf(psfile, "%%%%CreationDate: %s", ctime(&when));
  726.     fprintf(psfile, "%%%%For: %s@%s (%s)\n", who->pw_name, host, who->pw_gecos);
  727.     fprintf(psfile, "%%%%Pages: %d\n", 1);
  728.     fprintf(psfile, "%%%%BoundingBox: %d %d %d %d\n", llx, lly, urx, ury);
  729.     fprintf(psfile, "%%%%EndComments\n");
  730.     fprintf(psfile, "%s\n", BEGIN_PROLOG);
  731.  
  732.     fprintf(psfile, "/Nodefont");
  733.     fprintf(psfile, TEXT_PS, font, charysize);
  734.     fprintf(psfile, "/Edgefont");
  735.     fprintf(psfile, TEXT_PS, font, echarysize);
  736.  
  737.     if (ellipse_exist(digraph)) 
  738.     {
  739.     fprintf(psfile, "%s\n", ELLIPSE_PS);
  740.     }
  741.  
  742.     fprintf(psfile, "%s\n", END_PROLOG);
  743.     fprintf(psfile, "$XgrabpsBegin\n");
  744.  
  745.     if (landscapePSFile)
  746.     {    
  747.         fprintf(psfile, "%d 0 translate 90 rotate\n", PAGE_WIDTH);
  748.     }
  749.   /* end f2ps material */
  750.  
  751.       /* clipping box */
  752.     fprintf(psfile, "newpath %d %d moveto ", llx - 1, lly - LABELY - 1);
  753.     fprintf(psfile, "%d %d lineto ", urx + LABELX + 1, lly - LABELY - 1);
  754.     fprintf(psfile, "%d %d lineto ", urx + LABELX + 1, ury + 1);
  755.     fprintf(psfile, "%d %d lineto ", llx - 1, ury + 1);
  756.     fprintf(psfile, "%d %d lineto clip\n", llx - 1, lly - LABELY - 1);
  757. }
  758.  
  759.   /* begin f2ps material */
  760.  
  761. epilog()
  762.   /* write the ending postscript magic */
  763. {
  764.     if (show_page) 
  765.     {
  766.     fprintf(psfile, "showpage\n");
  767.     }
  768.  
  769.     fprintf(psfile, "$XgrabpsEnd\n");
  770. }
  771.  
  772. set_style(b, c)
  773. BRUSH b;
  774. COLOR c;
  775.   /* set the brush and color */
  776. {
  777.     if (b == DASHEDB || b == BDASHEDB)
  778.     {
  779.     fprintf(psfile, "\t[%d] 0 setdash\n", 4);
  780.     }
  781.     else if (b == DOTTEDB || b == BDOTTEDB) 
  782.     {
  783.     fprintf(psfile, "\t[%d] 0 setdash\n", 1);
  784.     }
  785.  
  786.     if (c == GRAY)
  787.     {
  788.     fprintf(psfile, "\t.5 setgray\n");
  789.     }
  790.     else if (c == WHITE)
  791.     {
  792.     fprintf(psfile, "\t1 setgray\n");
  793.     }
  794. }
  795.  
  796. reset_style(b, c)
  797.   /* change the brush and color back to normal */
  798. BRUSH b;
  799. COLOR c;
  800. {
  801.     if (b == DASHEDB || b == DOTTEDB || b == BDASHEDB || b == BDOTTEDB)
  802.     {
  803.         fprintf(psfile, "\t[] 0 setdash\n");
  804.     }
  805.  
  806.     if (c == GRAY || c == WHITE)
  807.     {
  808.     fprintf(psfile, "\t0 setgray\n");
  809.     }
  810. }
  811.  
  812. set_linewidth(b)
  813. BRUSH b;
  814.   /* set the thickness of the lines drawn */
  815. {
  816.     float w;
  817.  
  818.     if (b == BSOLIDB || b == BDASHEDB || b == BDOTTEDB)
  819.     {
  820.         w = 3.0;
  821.     }
  822.     else
  823.     {
  824.     w = 0.2;
  825.     }
  826.        
  827.     if (w != cur_thickness) 
  828.     {
  829.     cur_thickness = w;
  830.     fprintf(psfile, "%.3f setlinewidth\n", 0.4 * cur_thickness);
  831.     }
  832. }
  833.  
  834. ps_line(fromx, fromy, tox, toy, reversed, forward, brush, color)
  835. double fromx, fromy, tox, toy;
  836. BOOL reversed, forward;
  837. BRUSH brush;
  838. COLOR color;
  839.   /* draw a line */
  840. {
  841.     set_linewidth(brush);
  842.     set_style(brush, color);
  843.  
  844.     if (reversed)
  845.     {
  846.     draw_arrow_head(tox, toy, fromx, fromy);
  847.     }
  848.  
  849.     fprintf(psfile, "%% Polyline\n");
  850.     fprintf(psfile, "newpath %f %f moveto", fromx, fromy);
  851.     fprintf(psfile, " %f %f lineto stroke\n", tox, toy);
  852.  
  853.     if (forward)
  854.     {
  855.     draw_arrow_head(fromx, fromy, tox, toy);
  856.     }
  857.  
  858.     reset_style(brush, color);
  859. }
  860.  
  861.  
  862. ps_arc(centerx, centery, x1, y1, x2, y2, reversed, forward, brush, color)
  863. double centerx, centery, x1, y1, x2, y2;
  864. BOOL reversed, forward;
  865. BRUSH brush;
  866. COLOR color;
  867.   /* draw an arc */
  868. {
  869.     double angle1, angle2, dx, dy, radius, x, y;
  870.     int direction;
  871.  
  872.     direction = 1;        /* counterclockwise */
  873.  
  874.     set_linewidth(brush);
  875.     set_style(brush, color);
  876.  
  877.     if (forward)
  878.     {
  879.     arc_tangent(centerx, centery, x2, y2, direction, &x, &y);
  880.     draw_arrow_head(x, y, x2, y2);
  881.     }
  882.  
  883.     if (reversed)
  884.     {
  885.     arc_tangent(centerx, centery, x1, y1, !direction, &x, &y);
  886.     draw_arrow_head(x, y, x1, y1);
  887.     }
  888.  
  889.     dx = centerx - x1;
  890.     dy = centery - y1;
  891.     radius = sqrt(dx*dx + dy*dy);
  892.     angle1 = atan2(y1-centery, x1-centerx) * 180 / M_PI;
  893.     angle2 = atan2(y2-centery, x2-centerx) * 180 / M_PI;
  894.  
  895.       /* direction = 1 -> Counterclockwise */
  896.     fprintf(psfile, "newpath %.3f %.3f %.3f %.3f %.3f %s stroke\n",
  897.         centerx, centery, radius, angle1, angle2,
  898.         ((direction == 1) ? "arc" : "arcn"));
  899.     reset_style(brush, color);
  900. }
  901.  
  902. arc_tangent(x1, y1, x2, y2, direction, x, y)
  903. double x1, y1, x2, y2, *x, *y;
  904. int direction;
  905. {
  906.     if (direction)     /* counter clockwise  */
  907.     { 
  908.     *x = x2 + (y2 - y1);
  909.     *y = y2 - (x2 - x1);
  910.     }
  911.     else 
  912.     {
  913.     *x = x2 - (y2 - y1);
  914.     *y = y2 + (x2 - x1);
  915.     }
  916. }
  917.  
  918. #define DEFAHT 40.0
  919. #define DEFAWID 40.0
  920. #define MINAHT 2.0
  921. #define MINAWID 2.0
  922.  
  923. draw_arrow_head(x1, y1, x2, y2)
  924. double x1, y1, x2, y2;
  925.   /* draw an arrow on the line heading from (x1, y1) to (x2, y2) */
  926. {
  927.     float x, y, xb, yb, dx, dy, l, sina, cosa;
  928.     float xc, yc, xd, yd;
  929.     float arrowht, arrowwid;
  930.  
  931.     arrowht = DEFAHT / scaley > MINAHT ? DEFAHT / scaley : MINAHT;
  932.     arrowwid = DEFAWID / scalex > MINAWID ? DEFAWID / scalex : MINAWID;
  933.  
  934.     dx = x2 - x1;  dy = y1 - y2;
  935.     l = sqrt((double)(dx*dx + dy*dy));
  936.     sina = dy / l;  cosa = dx / l;
  937.     xb = x2 *cosa - y2 *sina;
  938.     yb = x2 *sina + y2 *cosa;
  939.     x = xb - arrowht;
  940.     y = yb - arrowwid / 2;
  941.     xc = x*cosa + y*sina;
  942.     yc = -x*sina + y*cosa;
  943.     y = yb + arrowwid / 2;
  944.     xd = x*cosa + y*sina;
  945.     yd = -x*sina + y*cosa;
  946.     fprintf(psfile, 
  947.         "newpath %.3f %.3f moveto %f %f lineto %.3f %.3f lineto stroke\n",
  948.         xc, yc, x2, y2, xd, yd);
  949. }
  950.  
  951. BOOL ellipse_exist(digraph)
  952. DIGRAPH *digraph;
  953.   /* return TRUE if there's an ellipse or circle in the graph */
  954. {
  955.     NODE *node;
  956.  
  957.     each_node(digraph, node)
  958.     loop
  959.     if (Shape(node) == OVAL || Shape(node) == CIRCLE)
  960.     {
  961.         return(TRUE);
  962.     }
  963.     endloop
  964.  
  965.     return(FALSE);
  966. }
  967.  
  968. ps_draw_oval(x_pos, y_pos, x_rad, y_rad, brush, color)
  969. float x_pos, y_pos, x_rad, y_rad;   /* center and radius */
  970. BRUSH brush;
  971. COLOR color;
  972.   /* draw an ellipse (circles are ellipses) */
  973. {
  974.     set_linewidth(brush);
  975.     set_style(brush, color);
  976.     fprintf(psfile, "%% Ellipse\n");
  977.     fprintf(psfile, "newpath %f %f %f %f 0 360 DrawEllipse stroke\n",
  978.         x_pos, y_pos, x_rad, y_rad);
  979.     reset_style(brush, color);
  980. }
  981.  
  982. ps_draw_rect(left, right, down, up, brush, color)
  983. float left, right, down, up;
  984. BRUSH brush;
  985. COLOR color;
  986.   /* draw a rectangle */
  987. {
  988.     set_linewidth(brush);
  989.     set_style(brush, color);
  990.  
  991.     fprintf(psfile, "%% Polyline\n");
  992.     fprintf(psfile, "newpath %f %f moveto", right, down);
  993.     fprintf(psfile, " %f %f lineto", right, up);
  994.     fprintf(psfile, " %f %f lineto", left, up);
  995.     fprintf(psfile, " %f %f lineto", left, down);
  996.     fprintf(psfile, " %f %f lineto stroke\n", right, down);
  997.  
  998.     reset_style(brush, color);
  999. }
  1000.  
  1001. ps_draw_diamond(xcenter, ycenter, left, down, right, up, brush, color)
  1002. float xcenter, ycenter, left, right, down, up;
  1003. BRUSH brush;
  1004. COLOR color;
  1005.   /* draw a diamond */
  1006. {
  1007.     set_linewidth(brush);
  1008.     set_style(brush, color);
  1009.  
  1010.     fprintf(psfile, "%% Polyline\n");
  1011.     fprintf(psfile, "newpath %f %f moveto", right, ycenter);
  1012.     fprintf(psfile, " %f %f lineto", xcenter, down);
  1013.     fprintf(psfile, " %f %f lineto", left, ycenter);
  1014.     fprintf(psfile, " %f %f lineto", xcenter, up);
  1015.     fprintf(psfile, " %f %f lineto stroke\n", right, ycenter);
  1016.  
  1017.     reset_style(brush, color);
  1018. }
  1019.  
  1020. /* end f2ps material */
  1021.